/*
 * WebSPHINX web crawling toolkit
 * Copyright (C) 1998,1999 Carnegie Mellon University 
 * 
 * This library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Library
 * General Public License as published by the Free Software 
 * Foundation, version 2.
 *
 * WebSPHINX homepage: http://www.cs.cmu.edu/~rcm/websphinx/
 */
package websphinx.util;

/**
 * String utility routines.
 */
public abstract class Str {

    /**
     * Find first occurence of any of a set of characters.
     * @param subject String in which to search
     * @param chars Characters to search for
     * @return index of first occurence in subject of a character from chars,
     * or -1 if no match.
     */
    public static int indexOfAnyChar (String subject, String chars) {
        return indexOfAnyChar (subject, chars, 0);
    }

    /**
     * Find first occurence of any of a set of characters, starting
     * at a specified index.
     * @param subject String in which to search
     * @param chars Characters to search for
     * @param start Starting offset to search from
     * @return index of first occurence (after start) in subject of a character from chars,
     * or -1 if no match.
     */
    public static int indexOfAnyChar (String subject, String chars, int start) {
        for (int i=start; i<subject.length(); ++i)
            if (chars.indexOf (subject.charAt (i)) != -1)
                return i;
        return -1;
    }

    /**
     * Replace all occurences of a string.
     * @param subject String in which to search
     * @param original String to search for in subject
     * @param replacement String to substitute
     * @return subject with all occurences of original replaced by replacement
     */
    public static String replace (String subject, String original, String replacement) {
        StringBuffer output = new StringBuffer ();

        int p = 0;
        int i;
        while ((i = subject.indexOf (original, p)) != -1) {
            output.append (subject.substring (p, i));
            output.append (replacement);
            p = i + original.length();
        }
        if (p < subject.length ())
            output.append (subject.substring(p));
        return output.toString ();
    }

    /**
     * Escapes metacharacters in a string.
     * @param subject String in which metacharacters are to be escaped
     * @param escapeChar the escape character (e.g., \)
     * @param metachars the metacharacters that should be escaped
     * @return subject with escapeChar inserted before every character found in metachars
     */
    public static String escape (String subject, char escapeChar, String metachars) {
        StringBuffer output = new StringBuffer ();

        int p = 0;
        int i;
        while ((i = indexOfAnyChar (subject, metachars, p)) != -1) {
            output.append (subject.substring (p, i));
            output.append (escapeChar);
            output.append (subject.charAt (i));
            p = i + 1;
        }
        if (p < subject.length ())
            output.append (subject.substring(p));
        return output.toString ();
    }

    /**
     * Parse a number from a string. Finds the first recognizable base-10 number (integer or floating point) 
     * in the string and returns it as a Number.
     * @param string String to parse
     * @return first recognizable number
     * @exception NumberFormatException if no recognizable number is found
     */
    private static final int INT = 0;
    private static final int FRAC = 1;
    private static final int EXP = 2;
    public static Number parseNumber (String s) throws NumberFormatException {
        int p = 0;
        for (int i=0; i<s.length(); ++i) {
            char c = s.charAt (i);
            if (Character.isDigit (c)) {
                int start = i;
                int end = ++i;
                int state = INT;

                if (start > 0 && s.charAt (start-1) == '.') {
                    --start;
                    state = FRAC;
                }
                if (start > 0 && s.charAt (start-1) == '-')
                    --start;

              foundEnd:
                while (i < s.length()) {
                    switch (s.charAt (i)) {
                      case '0': case '1': case '2': case '3': case '4':
                      case '5': case '6': case '7': case '8': case '9':
                        end = ++i;
                        break;
                      case '.':
                        if (state != INT)
                            break foundEnd;
                        state = FRAC;
                        ++i;
                        break;
                      case 'e':
                      case 'E':
                        state = EXP;
                        ++i;
                        if (i < s.length() && 
                            ( (c = s.charAt (i)) == '+' || c == '-') )
                          ++i;
                        break;
                      default:
                        break foundEnd;
                    }
                }
                
                String num = s.substring (start, end);
                try {
                    if (state == INT)
                        return new Integer (num);
                    else
                        return new Float (num);
                } catch (NumberFormatException e) {
                    throw new RuntimeException ("internal error: " + e);
                }
            }
        }
        throw new NumberFormatException (s);
    }

    public static void main (String[] args) {
      for (int i=0; i<args.length; ++i)
          System.out.println (parseNumber (args[i]));
  }
}
